

#include "FilePath.h"

#include <windows.h>
#include <stdio.h>

using namespace Pan;

FilePath FilePath::this_exe_file_path()
{
    FilePath fp(NULL);
    wchar_t *head = const_cast<wchar_t *>(fp.full_path());
    DWORD len = ::GetModuleFileNameW(nullptr, head, fp.default_buffer_size);

    if (len > 0 && len < fp.default_buffer_size)
        FilePath::remove_tail_backslash(head, len);

    return fp;
}

FilePath FilePath::working_directory()
{
    return FilePath(L".");
}

unsigned int FilePath::remove_extension(wchar_t *const path, unsigned int len)
{
    // 检查空指针
    if (path == nullptr || path[0] == '\0')
        return 0;

    if (len <= 0)
    { // 要求计算出字符串的长度
        while (path[len] != '\0')
            ++len;
    }

    // 移动指针到最后一个点（如果有的话）
    // 考虑一种特殊情况
    // "C:\\abc.def\\qq"
    while (path[len] != '.' && path[len] != '\\' && len > 0)
        --len;

    if (len > 0 && path[len] == '.')
    {                      // 字符串开头的点.是不处理的
        path[len] = L'\0'; // 设置为字符串的结束符
        return len;
    }
    else
    { // 没有找到那个点
        return 0;
    }
}

unsigned int FilePath::remove_tail_backslash(wchar_t *path, unsigned int len)
{
    // 参数检查：空指针或空字符串
    if (path == nullptr || path[0] == L'\0')
        return 0;

    // 计算字符串的长度
    if (len <= 0)
    {
        for (len = 0; len < FilePath::default_buffer_size; len++)
        {
            if (path[len] == '\0')
                break;
        }

        if (len <= 0)
            return 0;

        // 超出最长字符串限制
        if (len >= FilePath::default_buffer_size)
            return 0;
    }

    if (path[len - 1] != '\\')
        return len;

    if (len > 1 && path[len - 2] == ':')
        return len;

    path[--len] = '\0';

    return len;
}

unsigned int FilePath::add_tail_backslash(wchar_t *path, unsigned int len)
{
    if (path == nullptr || path[0] == L'\0')
        return 0; // 参数检查

    if (len <= 0)
    {
        // 计算字符串的长度
        while (path[len] != L'\0')
            ++len;
    }

    if (len > 0)
    {
        if (path[len - 1] != L'\\')
        {
            path[len++] = L'\\', path[len] = L'\0';
        }
        return len;
    }
    return len;
}

const wchar_t *FilePath::find_file_name(const wchar_t *path, unsigned int len)
{
    // 参数检查
    if (path == nullptr || *path == '\0')
        return nullptr;

    // 没有指定字符串的长度，自动计算字符串的长度
    if (len <= 0)
    {
        for (len = 0; path[len] != '\0'; len++)
            ;
    }

    for (len -= 1; len > 0; len--)
    {
        if (path[len] == '\\')
            break;
    }

    if (path[len] == '\\')
    {
        return &path[++len];
    }

    return nullptr;
}

const wchar_t *FilePath::find_extension(const wchar_t *path, unsigned int len)
{

    unsigned int &i(len);

    // 计算字符串的长度
    if (i <= 0)
    {
        while (i < FilePath::default_buffer_size && path[i] != L'\0')
            ++i;
    }

    while (i > 0)
    {
        if (path[i] == '\\')
        {
            break;
        }

        if (path[i] == '.')
        {
            return &path[i];
        }

        i--;
    }

    return nullptr;
}

FilePath::FilePath(const wchar_t *path) : fp(nullptr)
{
    // 分配内存
    this->fp = new wchar_t[this->default_buffer_size];

    // 内存分配失败
    if (this->fp == nullptr)
        return;

    // 转化为绝对路径
    if (path != NULL && *path != '\0')
    {
        DWORD len = ::GetFullPathNameW //
            (
                path,
                this->default_buffer_size,
                this->fp,
                NULL //
            );

        if (len > 0 && len < this->default_buffer_size)
        {
            // 转化成功，去除最后的反斜杠（如果它有的话）
            this->remove_tail_backslash(this->fp, len);
        }
        else
        { // 转化失败
            this->fp[0] = '\0';
        }
    }
    else
    {
        this->fp[0] = '\0';
    }
}

Pan::FilePath::~FilePath()
{
    // 释放内存
    if (this->fp != nullptr)
    {
        delete[] this->fp, this->fp = nullptr;
    }
}

unsigned int Pan::FilePath::append_node(const wchar_t *name) const
{
    unsigned int i;

    for (i = 0; i < this->default_buffer_size; i++)
    {
        if (this->fp[i] == '\0')
            break;
    }

    if (i > 0 && i + 1 < this->default_buffer_size && this->fp[i - 1] != '\\')
    {
        this->fp[i++] = '\\';
        this->fp[i] = '\0';
    }

    if (i == 0 && i + 1 < this->default_buffer_size)
    {
        this->fp[i++] = '\\';
        this->fp[i] = '\0';
    }

    if (name != nullptr)
    {
        unsigned int k = 0;
        while (i < this->default_buffer_size && (this->fp[i] = name[k]) != '\0')
        {
            ++i;
            ++k;
        }
    }

    return i;
}

bool Pan::FilePath::to_parent_path() const
{

    unsigned int i;

    // 移动到末尾
    for (i = 0; i < this->default_buffer_size; i++)
    {
        if (this->fp[i] == '\0')
            break;
    }

    // 超出缓冲区
    if (i >= this->default_buffer_size)
        return false;

    // 只有一个字符串不处理
    if (i <= 1)
        return false;

    // 移动到最后一个反斜杠'\\'

    // 跳过最后一个字符
    for (i -= 2; i > 0; --i)
    {
        if (this->fp[i] == '\\')
            break;
    }

    // 哪怕第一个字符是反斜杠也不处理
    if (i == 0)
        return false;

    if (this->fp[i] != '\\')
        return false;

    // D:\\test
    if (i > 0 && this->fp[i - 1] == ':')
    {
        this->fp[i + 1] = '\0';
    }
    else
    {
        // D:\\test\\test.exe
        this->fp[i] = '\0';
    }
    return true;
}
